home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / batchut / rbsetnv1.zip / COMSUB.C < prev    next >
Text File  |  1991-01-03  |  7KB  |  244 lines

  1. /*
  2.  * comsub.c - routines to perform command substitution and environment variable
  3.  *              parsing and expansion
  4.  *
  5.  * Author:    R. Brittain 4/11/90
  6.  *            This code placed in the public domain
  7.  *
  8.  */
  9. #include <string.h>
  10. #include <ctype.h>
  11. #include <stdlib.h>
  12.  
  13. #include "comsub.h"
  14.  
  15. int rebuild_argv(int *argc, char ***argv)
  16. {
  17. /*
  18.  * Build a new argv array, by iteratively performing backquote expansion
  19.  * and environment variable expansion until no more is possible.
  20.  * We always replace argv[] at least once, because the routine terminates it
  21.  * with an extra null, which is useful later for exec()ing.
  22.  * Returns the number of substitutions performed
  23.  */
  24.     int i, count = 0, subst;
  25.  
  26.     count += expand_backquotes(argc, argv);
  27.     do {
  28.         subst = FALSE;
  29.         /* look for any argument beginning with BKQ or ENV */
  30.         for (i=0; i < *argc; i++) {
  31.             if (*(*argv)[i] == BKQ || *(*argv)[i] == ENV ) {
  32.                 subst = TRUE;
  33.                 break;
  34.             }
  35.         }
  36.         if (subst) count += expand_backquotes(argc, argv);
  37.     } while (subst);
  38.     return(count);
  39. }
  40.  
  41.  
  42. int expand_backquotes(int *argc, char ***argv)
  43. {
  44. /*
  45.  * Perform command substitution if any argument begins with BKQ (`)
  46.  * Perform environment variable expansion if an argument begins with ENV (%)
  47.  * Returns the number of substitutions performed
  48.  * This routine would be simpler if backquoted commands were always parsed
  49.  * as a single command line argument, but doing it here means we don't need
  50.  * to modify the startup code.
  51.  */
  52.     char **base, *p, *result;
  53.     estring command = {NULL, NULL, 0, 80};
  54.     int  i, j, status = 0;
  55.     FILE *fp;
  56.  
  57.     MEMCHECK(base  = (char **) malloc(sizeof(char **))) ;
  58.     *base = NULL;
  59.     for (i=0, j=0; i < *argc; i++) {
  60.         if (*(*argv)[i] == BKQ) {
  61.             /*
  62.              * first character is a BKQ - we have a request for command
  63.              * substitution so build command in an estring structure
  64.              */
  65.             status++;
  66.             MEMCHECK( addstring(&command, (*argv)[i]+1, 0) );
  67.             if (*command.b == EXE) {
  68.                 set_popen_exec();
  69.                 command.b++;
  70.             } else {
  71.                 set_popen_shell();
  72.             }
  73.             /*
  74.              * if this argument ends with a second BKQ, remove it
  75.              * otherwise, scan forward for an argument terminated by BKQ,
  76.              * appending to command as we go
  77.              */
  78.             if (*(p = endptr(command.b)-1) == BKQ) {
  79.                 *p = '\0';
  80.             } else {
  81.                 do {
  82.                     /* increment argument pointer and append to current command */
  83.                     if ( i++ >= *argc) fatal("Unterminated command substitution",1);
  84.                         /* we ran out of arguments before finding BKQ */
  85.                     MEMCHECK(addstring(&command," ",1));
  86.                     MEMCHECK(addstring(&command,(*argv)[i], 0));
  87.                 } while (*(endptr((*argv)[i])-1) != BKQ);
  88.                 /* now stomp on of the trailing backquote */
  89.                 if (*(p = endptr(command.b)-1) == BKQ) *p = '\0';
  90.             }
  91.  
  92.             /* perform variable substitution then run the command via popen */
  93.             command.b = expand_env(command.b);
  94.             if ((fp = popen(command.b, "r")) == NULL) {
  95.                 fputs (command.b, stderr);
  96.                 fatal(": popen failed: \n",1);
  97.             }
  98.             result = mfgets(fp);
  99.             pclose(fp);
  100.  
  101.             /* now parse <result> for whitespace and treat as new arguments */
  102.             p = strtok(result," \t");
  103.             while (p != NULL) {
  104.                 MEMCHECK(base = (char **)realloc(base,(j+2)*sizeof(char **))) ;
  105.                 MEMCHECK(base[j++] = strdup(p)) ;
  106.                 base[j] = (char *)NULL;
  107.                 p = strtok(NULL," \t");
  108.             }
  109.  
  110.         } else if (*(*argv)[i] == ENV) {
  111.             /* we have a request for environment substitution */
  112.             status++;
  113.             result = expand_env((*argv)[i]);
  114.             /* now parse <result> for whitespace and treat as new arguments */
  115.             p = strtok(result," \t");
  116.             while (p != NULL) {
  117.                 MEMCHECK(base = (char **)realloc(base,(j+2)*sizeof(char **))) ;
  118.                 MEMCHECK(base[j++] = strdup(p)) ;
  119.                 base[j] = (char *)NULL;
  120.                 p = strtok(NULL," \t");
  121.             }
  122.  
  123.         } else {
  124.             /* grab one more pointer, add to base array, and copy this argument */
  125.             MEMCHECK(base = (char **)realloc(base,(j+2)*sizeof(char **))) ;
  126.             base[j++] = (*argv)[i];
  127.             base[j] = (char *)NULL;
  128.         }
  129.     }
  130.     *argv = base;
  131.     *argc = j;
  132.     return(status);
  133. }
  134.  
  135.  
  136. char *endptr(p)
  137. char *p;
  138. {
  139.     while (*p) p++;
  140.     return p;
  141. }
  142.  
  143.  
  144. char *mfgets (FILE *stream)
  145. {
  146. /*
  147.  * Suck in the entire file, replacing newlines by spaces
  148.  * and allocating memory as needed
  149.  */
  150.     estring contents = {NULL, NULL, 0, 132};
  151.     char line[132];
  152.  
  153.     if (feof(stream)) return NULL;
  154.     while (fgets(line,sizeof(line),stream) != NULL) {
  155.         if (*(endptr(line)-1) == '\n') *(endptr(line)-1) = ' ';
  156.         addstring(&contents,line,strlen(line));
  157.     }
  158.     return(contents.b);
  159. }
  160.  
  161.  
  162. char *expand_env(char *s)
  163. {
  164. /*
  165.  * Scan string s for '%' (or ENV) and expand environment variables as found
  166.  * Return a pointer to the expanded string (which may be the same as the input)
  167.  * The input string is left intact
  168.  */
  169.     char *r;
  170.     estring result = {NULL, NULL, 0, 128};
  171.     estring var = {NULL, NULL, 0, 64};
  172.  
  173.     result.p = result.b;
  174.     if (strchr(s,ENV) == NULL) {
  175.         /*
  176.          * nothing to do
  177.          */
  178.         return(s);
  179.     } else {
  180.         /*
  181.          * we have some vars to substitute - parse into words by whitespace
  182.          * and examine each one
  183.          */
  184.         while (*s) {
  185.             if (*s == ENV) {
  186.                 /* some work to do */
  187.                 if (*(++s) == ENV) {
  188.                     /* double ENV */
  189.                     MEMCHECK(addstring(&result, s++, 1));
  190.                 } else {
  191.                     /* look for next whitespace or ENV */
  192.                     var.b = var.p;
  193.                     while (*s && *s != ENV && !isspace(*s)) {
  194.                         addstring(&var, s++, 1);
  195.                     }
  196.                     /* copy over the variable value, if non null */
  197.                     if ((r = getenv(strupr(var.b))) != NULL)
  198.                         MEMCHECK(addstring(&result,r,strlen(r)));
  199.                     /* examine how the var name was terminated */
  200.                     if (*s == ENV && isspace(*(s+1))) {
  201.                         /* redundant trailing ENV - skip over */
  202.                         s++;
  203.                     }
  204.                 }
  205.             } else {
  206.                 /* just copy characters */
  207.                 MEMCHECK(addstring(&result, s++, 1));
  208.             }
  209.         }
  210.         return(result.b);
  211.     }
  212. }
  213.  
  214. char *addstring(estring *es, char *add, int count)
  215. {
  216. /*
  217.  * Add <count> characters from string <add> to estring <es>
  218.  * <es> is extended automatically as needed
  219.  * Returns a pointer to the start of the string (NULL if an expansion failed)
  220.  * If the count is zero, then it is taken to be strlen(add) by default
  221.  */
  222.     if (count == 0) count = strlen(add);
  223.  
  224.     if (es->p - es->b + count >= es->len) {
  225.         if (es->p != NULL) {
  226.             /* we are expanding */
  227.             *es->p = '\0';
  228.             es->b = (char *)realloc(es->b, es->len + max(es->inc, count+1));
  229.             if (es->b == (char *)NULL) return (NULL);
  230.             es->p = endptr(es->b);
  231.             es->len += es->inc;
  232.         } else {
  233.             /* we are making initial allocation */
  234.             es->p = es->b = (char *)calloc(max(es->inc,count+1), 1);
  235.             if (es->b == (char *)NULL) return (NULL);
  236.             es->len = es->inc;
  237.         }
  238.     }
  239.     strncpy(es->p, add, count);
  240.     es->p += count;
  241.     *es->p = '\0';
  242.     return(es->b);
  243. }
  244.